import socket, random , pickle, time, msvcrt, os, copy
import bguiconfig
from Vue.Vue import *
from Modele.Modele import *
from Modele.Entite.Joueur import *
from Modele.Entite.Personnage import *
nameList = ["Redyz", "Superman", "Carl", "Gaytan", "Jean-Claude", "Henry", "Doodle", "McBob", "JeanMarc", "Samsung", "Fookme", "Fookyu","Austin", "Trull"]


class Client:
	def __init__(self):
		self.socket = 0
		self.user_name = ""
		self.nomEntite = "" #nom du joueur
		self.donnees = "" #string des messages
		self.exit = False
		self.vue = Vue(self)
		self.modele = Modele(self)
		self.Personnage = Personnage(self)
		self.seed = 0
		
		self.currentFrame = 0
		self.commandesSuivantes = list()# à 0 = frame, reste = actions
		
		self.nombreMessagesEnvoyes = 0 #variable debug: nombre de donnes envoyes
		self.nombreMessagesRecus = 0 #variable debug: nombre de donnes envoyes

	def connect(self, user_name, serveur_ip, serveur_port): #permet la connexion au serveur
		self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		self.socket.setblocking(False)

		self.user_name = user_name
		self.serv_addr = (serveur_ip, int(serveur_port))
		self.ajoutMessage("Connexion") #ajout du message de connexion
	def ajoutMessage(self, typeMessage, info=0, messageChat=""): #permet d'ajouter des messages a la queue d'envoi
		self.nombreMessagesEnvoyes += 1
		if typeMessage == "Connexion":
			self.donnees += "#CON:" + str(self.user_name)
		elif typeMessage == "Message":
			self.donnees += "#MES:" + messageChat
		elif typeMessage == "Demmarer":
			self.donnees += "#DEM:"
		elif typeMessage == "Actions":#ajoute les actions determiner par les touches du clavier/position de la souris
			self.donnees += "#ACT:"
			self.donnees += str(self.nomEntite)+ ";"
			for action in info:#les actions qu'ont lui donne sont inscrit dans le message (example : tournerG)
				self.donnees += action+ "/"
			self.donnees = self.donnees[:-1]
		elif typeMessage == "Pickup":
			self.donnees += "#PIC:" + info #nom de l'entite pickup
		elif typeMessage == "Attack":
			self.donnees += "#ATT:" + info
		elif typeMessage == "Teleport":
			self.donnees += "#TEL:" + info #info est le nom de l'entite, 99% du temps c'est l'entite du joueur locale
			
		else:
			print("Message non implementer :", typeMessage)
	def send(self):#methode qui envoi les messages au serveur
		if (GLOB.partieEnCours):
			self.donnees = "#FRA:" + str(self.currentFrame) + self.donnees
		if len(self.donnees) is not 0:
			#print("DONNEES CLIENT: ",self.donnees)
			self.socket.sendto(pickle.dumps(self.donnees), self.serv_addr)
			#if self.currentFrame == 5:
				#self.socket.setblocking(True)
				#print("SETBLOCKING IS NOW TRUE")			#envoi au serveur
			self.donnees = "" #on vide les references, mais les objets referencers existent encore
	def receive(self):
	
		messageTrouver = False
		while (messageTrouver == False):
			if GLOB.partieEnCours == False:
				messageTrouver = True
			try:
				data, addr = self.socket.recvfrom(1024) #1024 bytes; 1KB
				dataString = pickle.loads(data)#CHECK si pickle est utile
				dataList = dataString.split("#")
				#print("DATALIST: ",dataList)
				for message in dataList:
					self.nombreMessagesRecus += 1
					header = "[" + str(time.strftime('%X')) + "] "
					if message.find("CON") > -1:
						message = message[4:]
						GLOB.nombreJoueurs = int(message)
					elif message.find("MES")> -1:
						message = message[4:]
						bguiconfig.refreshMessage(message)
					elif message.find("ACK") > -1:
						message = message[4:]
						self.nomEntite = "Joueur"+ str(message)
						print("Votre entite est " + str(self.nomEntite))
					elif message.find("DEM") > -1:
						message = message[4:]
						GLOB.partieEnCours = True
						self.demarrageJeu(int(message))
					elif message.find("FRA") > -1:
						message = message[4:]
						if int(message) == self.currentFrame:
							messageTrouver = True
							#print("Message recu pour la frame courante")
					elif message.find("FRR") > -1:
						messages = copy.copy(dataList)
						messages.remove(message)
						message = message[4:]
						messages.insert(0,str(message))
						self.commandesSuivantes.append(messages)
					elif message.find("FER") > -1:
						message = message[4:]
						print("Fermeture du serveur")
					elif message.find("PIC") > -1:
						message = message[4:]
						self.vue.detruireObjet(message)
						self.modele.detruireEntite(message)
					elif message.find("ATT") > -1:
						message = message[4:]
						
						destinataire = ''
						degat = ''
						for i in range(0,len(message)):
							if message[i] not in ';':
								destinataire += message[i]
							else:
								for j in range(i+1,len(message)):
									if message[j] is not ';':
										degat += message[j]
								break
						if destinataire.find("Gardien")> -1:
							pass
						else:
							self.modele.entites[destinataire].modVie(int(degat)*-1)#A changer!!!!
				else:
					pass
						#print("MESSAGE: " + str(message))		
				dataList = "" #pas vraiment necessaire
			
			except socket.error: #exception, on ne reçoit plus rien
				break;
			#break #on sort du loop
	def quit(self):
		print("Exiting client...")
		print("Sending quit packet...")
		self.send()#send quit packet
		print("Closing socket...")
		self.socket.close() #deconnexion, fermeture du socket
		print("Done!")
	def mainLoop(self):
		if GLOB.partieEnCours:
			self.vue.verifierVie()
			#methodes qui regarde le clavier et la souris pour determiner les actions a effectuer localement
			self.vue.regarderPourTouches()
			self.vue.regarderPourSouris()
			#Effectue les actions selons les touches du clavier et les actions de la souris
			Joueur = self.modele.entites[self.nomEntite]
			self.vue.updateHUD(vie=Joueur.vie, nbrBallePistolet=Joueur.pistolet.balles, nbrBalleMp78=Joueur.fusil.balles, nbrEnergie=Joueur.energie.quantite, nbrMetal=Joueur.metal.quantite)
			Joueur.clavier = self.vue.cleEnCours
			self.vue.cleEnCours = dict()#Vide le dictionnaire pour eviter que les actions se repetent
			ActionsAEnvoyer = Joueur.traitementClavier()#Determine les actions a partir des commandes
			if len(ActionsAEnvoyer) is not 0:#Si on a bel et bien de nouvelles actions
				self.ajoutMessage("Actions",ActionsAEnvoyer)#on l'envoie au serveur

			#Actions apres demarrage
			self.traitementActionsSuivantes()
			self.currentFrame += 1
		self.send()
		self.receive()
		if self.currentFrame % 10 == 0:
			pass #mise en commentaire des infos suivante afin de pouvoir debug!
			#print("RECU: " + str(self.nombreMessagesRecus))
			#print("ENVOYE: " + str(self.nombreMessagesEnvoyes))
			
		#Deplement de la balle
		for balle in self.modele.listeBalles:
			balle.teleporterBalle()
			self.vue.teleporterObjet(balle.id, balle.position)
			
	def demarrageJeu(self,nbDeJoueurs):
		#Creation de chacune des entites et des elements du decor
		
		self.modele.map = Map(self)
		self.modele.map.creationEtage(self,"Force", 13)
		Etage1 = self.modele.map.dictEtages.get("Force")
		zones =  self.modele.map.dictEtages.get("Force").matriceZones
		
		for ligneZone in zones:
			for zoneCourante in ligneZone:
				if len(zoneCourante.type) != 0:
					if zoneCourante.type == "m":
						type = "Mur"
						self.vue.creerCube(zoneCourante.nom,type,zoneCourante.position+[0],[(i+zoneCourante.taille[0]) for i in zoneCourante.position]+[5])
					elif zoneCourante.type == "p":
						type = "Porte"
						self.vue.creerCube(zoneCourante.nom,type,zoneCourante.position+[0],[(i+zoneCourante.taille[0]) for i in zoneCourante.position]+[5])
		
		
		self.modele.map.creationEtage(self,"Resilience",13)
		Etage2 = self.modele.map.dictEtages.get("Resilience")
		zones = self.modele.map.dictEtages.get("Resilience").matriceZones
		
		for ligneZone in zones:
			for zoneCourante in ligneZone:
				if len(zoneCourante.type) != 0:
					if zoneCourante.type == "m":
						type = "Mur"
						self.vue.creerCube(zoneCourante.nom,type,zoneCourante.position+[0],[(i+zoneCourante.taille[0]) for i in zoneCourante.position]+[5])
					elif zoneCourante.type == "p":
						type = "Porte"
						self.vue.creerCube(zoneCourante.nom,type,zoneCourante.position+[0],[(i+zoneCourante.taille[0]) for i in zoneCourante.position]+[5])
		
		
		self.modele.map.creationEtage(self,"Intelligence",13)
		Etage3 = self.modele.map.dictEtages.get("Intelligence",13)
		zones = self.modele.map.dictEtages.get("Intelligence").matriceZones
		
		for ligneZone in zones:
			for zoneCourante in ligneZone:
				if len(zoneCourante.type) != 0:
					if zoneCourante.type == "m":
						type = "Mur"
						self.vue.creerCube(zoneCourante.nom,type,zoneCourante.position+[0],[(i+zoneCourante.taille[0]) for i in zoneCourante.position]+[5])
					elif zoneCourante.type == "p":
						type = "Porte"
						self.vue.creerCube(zoneCourante.nom,type,zoneCourante.position+[0],[(i+zoneCourante.taille[0]) for i in zoneCourante.position]+[5])

						
		self.modele.map.creationEtage(self,"Sagesse",13)
		Etage4 = self.modele.map.dictEtages.get("Sagesse",13)
		zones = self.modele.map.dictEtages.get("Sagesse").matriceZones

		for ligneZone in zones:
			for zoneCourante in ligneZone:
				if len(zoneCourante.type) != 0:
					if zoneCourante.type == "m":
						type = "Mur"
						self.vue.creerCube(zoneCourante.nom,type,zoneCourante.position+[0],[(i+zoneCourante.taille[0]) for i in zoneCourante.position]+[5])
					elif zoneCourante.type == "p":
						type = "Porte"
						self.vue.creerCube(zoneCourante.nom,type,zoneCourante.position+[0],[(i+zoneCourante.taille[0]) for i in zoneCourante.position]+[5])		
		
		self.vue.creerCube("Force","Plancher",[0,0,0],Etage1.taille+[0.5])
		for joueur in range(0,nbDeJoueurs):
			nouvJoueur = self.modele.creerEntite("JoueurH")
			self.vue.creerJoueur(nouvJoueur.nom,nouvJoueur.nom,nouvJoueur.position)
			GLOB.currentJoueur += 1
		entiteLogomate = self.modele.creerEntite("LogomateGentil")
		logomate = self.vue.creerLogomate(entiteLogomate.nom, "Logomate", [entiteLogomate.position[0],entiteLogomate.position[1],entiteLogomate.position[2]])
		print("Objets créés")
		entiteGardien = self.modele.creerEntite("LogomateGardien")
		gardien = self.vue.creerGardien(entiteGardien.nom, "Gardien", [entiteGardien.position[0],entiteGardien.position[1],entiteGardien.position[2]])
		self.vue.activeCamera(self.nomEntite)
		self.vue.activerHUD()
		#debuging
		entite = self.modele.creerEntite("Soins", position=[20,20,1], rotation=0)
		self.vue.creerObjet(entite.nom, "Soins", position=entite.position, scale=[1,1,1], layer=1, rotation=0)
		
		for index in range(10):
			entite = self.modele.creerEntite("Munitions", position=[37+index,37+index,1], rotation=0)
			self.vue.creerObjet(entite.nom, "Munitions", position=[37+index,37+index,0], scale=[1,1,1], layer=1, rotation=0)
		
		
		#Force->Resilience
		entite = self.modele.creerEntite("Teleport", position=[35, 35, 0], rotation=45, info=[213, 14, 0])
		self.vue.creerObjet(entite.nom, "Teleport", entite.position, scale=[1,1,1], layer=1, rotation=entite.rotation)

		#Resilience->Force
		entite = self.modele.creerEntite("Teleport", position=[213, 16, 0], rotation=0, info=[35, 35, 0])
		self.vue.creerObjet(entite.nom, "Teleport", entite.position, scale=[1,1,1], layer=1, rotation=entite.rotation)
		
		#Resilience->Intelligence
		entite = self.modele.creerEntite("Teleport", position=[305, 118, 0], rotation=90, info=[465, 12, 0])
		self.vue.creerObjet(entite.nom, "Teleport", entite.position, scale=[1,1,1], layer=1, rotation=entite.rotation)
		
		#Intelligence->Resilience
		entite = self.modele.creerEntite("Teleport", position=[465, 12, 0], rotation=90, info=[305, 118, 0])
		self.vue.creerObjet(entite.nom, "Teleport", entite.position, scale=[1,1,1], layer=1, rotation=entite.rotation)
		
		#Intelligence->Sagesse
		entite = self.modele.creerEntite("Teleport", position=[462, 118, 0], rotation=90, info=[669, 14, 0])
		self.vue.creerObjet(entite.nom, "Teleport", entite.position, scale=[1,1,1], layer=1, rotation=entite.rotation)
		
	def traitementActionsSuivantes(self):
		commandesTemp = copy.copy(self.commandesSuivantes)
		if commandesTemp:
			#print("CommandesTemps : ",commandesTemp)
			for listeCommandes in commandesTemp:
				#print("listeCommandes ", listeCommandes[0])
				#print("currentFrame ",self.currentFrame)
				if int(listeCommandes[0]) == self.currentFrame:
					for commande in listeCommandes:
						if commande.find("ACT") > -1:
							commande = commande[4:]
							listeInfo = commande.split(";")#NomJoueur,action/action/action/action/etc
							nomJoueur = listeInfo[0]
							#print("NOM DU JOUEUR :",nomJoueur)
							actJoueur = listeInfo[1].split("/")
							#print("EXECUTION")
							changements = self.modele.entites[nomJoueur].traitementActions(actJoueur)
							if changements.find("dep") > -1:
								self.vue.teleporterObjet(nomJoueur,self.modele.entites[nomJoueur].position)
							if changements.find("rot") > -1:
								self.vue.tournerObjet(nomJoueur,self.modele.entites[nomJoueur].rotation)
							if changements.find("car") > -1:
								self.vue.changerArme(nomJoueur,self.modele.entites[nomJoueur].armeEnMain)
							if changements.find("tel") > -1:
								self.vue.teleporterObjet(nomJoueur,self.modele.entites[nomJoueur].position)
							if changements.find("soi") > -1:
								print("Joueur : "+nomJoueur+", a ete soigner")
							if changements.find("mun") > -1:
								print("Joueur : "+nomJoueur+", a pris des munitions")
						elif commande.find("LOG") >-1:
							logomateGentil = self.modele.entites["LogomateGentil1"]
							logomateGentil.execution()
							self.vue.teleporterObjet(logomateGentil.nom, logomateGentil.position)
							logomateGardien = self.modele.entites["LogomateGardien1"]
							logomateGardien.execution()
							cibleLogomate = self.vue.detecter(logomateGardien.nom)
							if cibleLogomate != "":
								logomateGardien.cibler(self.modele.entites[cibleLogomate])
							actionsGardien = logomateGardien.traitementActions()
							self.vue.teleporterObjet(logomateGardien.nom,logomateGardien.position)
							if actionsGardien.find("rot") > -1:
								self.vue.tournerGardien(logomateGardien.nom,[logomateGardien.destination[0],logomateGardien.destination[1],logomateGardien.position[2]])
					self.commandesSuivantes.remove(listeCommandes)

client = Client()
def initClient(user_name,serv_addr,serv_port):
	client.connect(user_name,serv_addr, serv_port)

def loopClient(): #blender gere le tick, ainsi il peut process ses affaire a lui 
	if GLOB.lobbyBool or GLOB.partieEnCours:
		client.mainLoop()

def ecrireMessage(text):
	client.ajoutMessage("Message",info=0,messageChat=text)

def demmarerPartie():
	client.ajoutMessage("Demmarer")

def cameraPosition():
	client.vue.cameraPosition()

def boneTracking():
	client.vue.boneTracking()
